package org.pcorp.battlespace.construction.service;

import java.util.LinkedList;
import java.util.List;

import org.pcorp.battlespace.construction.modele.SabordCstr;
import org.pcorp.battlespace.construction.modele.VaisseauCstr;
import org.pcorp.battlespace.modele.Equipement;
import org.pcorp.battlespace.modele.Vaisseau;
import org.pcorp.battlespace.modele.equipement.Armement;
import org.pcorp.battlespace.modele.equipement.Sabord;
import org.pcorp.battlespace.modele.equipement.Tourelle;
import org.springframework.stereotype.Component;

@Component("CalculConstructionFrp")
public class CalculConstructionFrp implements CalculConstructionAble {
	private static double KF_COMPACT=0.30; // original 0.4525
	private static double KF_STD=0.60;       // original 0.95
	private static double KF_COMPACT_INT=2;
	private static double KF_COMPACT_INT2=25000;
	private static double KF_STD_INT=1.2;
	private static double KF_STD_INT2=60000;
	private static double KF_COMPACT_VOILE=30;
    private static double KF_COMPACT_VOILE2=20000;
    private static double KF_STD_VOILE=30;
    private static double KF_STD_VOILE2=7500;
    private static double KF_VOILE_MASSE=20;
    private static double PROP_COEF=0.06;
    private static double COUCHE_BLI=300;
    private static long   INT_EMPLAC=1;
	
	private VaisseauCstr vaiss;
	private CalculEquipageAble calcEquip;
	
	public CalculConstructionFrp() {
	
	}
	
	public CalculConstructionFrp(VaisseauCstr vaiss) {
		init(vaiss);
	}
	
	public void init(VaisseauCstr vaiss) {
		this.vaiss = vaiss;
		calcEquip = new CalculEquipageFrappeur();
	}

	/* (non-Javadoc)
	 * @see org.pcorp.battlespace.construction.service.CalculConstructionAble#getVaiss()
	 */
	@Override
	public VaisseauCstr getVaiss() {
		return vaiss;
	}

	/* (non-Javadoc)
	 * @see org.pcorp.battlespace.construction.service.CalculConstructionAble#setVaiss(org.pcorp.battlespace.construction.modele.VaisseauConstruction)
	 */
	@Override
	public void setVaiss(VaisseauCstr vaiss) {
		this.vaiss = vaiss;
	}


	
	public long calculMasseDisponible() {
		//System.out.println("calcul masse dispo " + vaiss);
		long masseDispo = vaiss.getMasse();
		masseDispo -= vaiss.getKfMasse();
		masseDispo -= vaiss.getKfVoileMasse();
		masseDispo -= vaiss.getPropMasse();
		masseDispo -= vaiss.getPropReservoir();
		masseDispo -= vaiss.getStructureMasse();
		masseDispo -= vaiss.getBlindageMasse();
		masseDispo -= calculMasseArmement();
		masseDispo -= calculMasseEquipement();
		
		// TODO: ajouter les information sous-ensembles
		return masseDispo;
	}
	
	public long calculMassePropulsionKF() {
		//System.out.println("calcul masse propulsion KF : " + vaiss.isKf() + " - " + vaiss.isKfCompact() + " : " + vaiss.getMasse());
		if (!vaiss.isKf())
			return 0;
		if (vaiss.isKfCompact()) {
			return Math.round(vaiss.getMasse()*KF_COMPACT);
		}
		return Math.round(vaiss.getMasse()*KF_STD);
	}
	
	public long calculIntegriteKF() {
		if (!vaiss.isKf()) {
			return 0;
		}
		
		if (vaiss.isKfCompact()) {
			return Math.round(KF_COMPACT_INT+(vaiss.getKfMasse()/KF_COMPACT_INT2));
		}
		
		return Math.round(KF_STD_INT+(vaiss.getKfMasse()/KF_STD_INT2));
	}
	
	private long calculIntegriteVoile() {
		if (!vaiss.isKf()) {
			return 0;
		}
	
		return 1 + Math.round(vaiss.getKfVoileMasse()/KF_VOILE_MASSE);
	}
	
	public long calculMasseVoile() {
		if (!vaiss.isKf()) {
			return 0;
		}
		
		if (vaiss.isKfCompact()) {
			return Math.round(KF_COMPACT_VOILE+(vaiss.getMasse()/KF_COMPACT_VOILE2));
		}
		
		return Math.round(KF_STD_VOILE+(vaiss.getMasse()/KF_STD_VOILE2));
	}
	
	public long calculMassePropulseur() {
		return Math.round(vaiss.getPousse()*PROP_COEF*vaiss.getMasse());
	}
	
	public long calculReservoirReco() {
		long masseVx = vaiss.getMasse();
		if (masseVx<50000)
			return Math.round(2.82*20);
		if (masseVx<100000)
			return Math.round(9.77*20);
		if (masseVx<200000)
			return Math.round(19.75*20);
		return Math.round(39.52*20);
	}
	
	public long calculMasseStructure() {
		if (vaiss.isKfCompact())
			return Math.round((vaiss.getStructureIntegrite()/10f)*(vaiss.getMasse()/100f));
		return Math.round(vaiss.getMasse()/150);
	}
	
	public long calculMasseBlindage() {
		long masse = vaiss.getMasse();
		long blin  = vaiss.getBlindage();
		
		long x = Math.round(Math.cbrt(masse*9));
		long surface = 4*x*x/3+(x*x/9);
		
		// ici ajouter le type de bli
		double bliDensite = 0.300;
		long bliMasse = Math.round(surface*bliDensite*blin/COUCHE_BLI);
		
		/*if (masse < 15000)
			return Math.round(blin/1.6);
		if (masse < 150000)
			return Math.round(blin/0.8);
		if (masse < 250000)
			return Math.round(blin/0.6);*/
		
		return bliMasse;
	}
	
	public long calculMasseArmement() {
		long masse = 0;
		for (Sabord sab : vaiss.getSabords()) {
			for (Equipement equip : sab.getArmements()) {
				if (equip instanceof Tourelle) {
					long masseT = 0;
					for (Equipement arme : ((Tourelle)equip).getArmements()) {
						masseT += arme.getMasse();
					}
					masse += masseT*1.1;
				}
				else {
					masse += equip.getMasse();
				}
			}
		}
		return masse;
	}
	
	public long calculMasseEquipement() {
		long masse = 0;
		for (Equipement equip : vaiss.getEquipements()) {
			masse += equip.getMasse();
		}
		return masse;
	}
	

	@Override
	public void majCalculConstruction() {
		vaiss.setKfMasse(calculMassePropulsionKF());
		vaiss.setKfIntegrite(calculIntegriteKF());
		vaiss.setKfVoileMasse(calculMasseVoile());
		vaiss.setKfVoileIntegrite(calculIntegriteVoile());
		vaiss.setPropMasse(calculMassePropulseur());
		vaiss.setPropReservoirReco(calculReservoirReco());
		vaiss.setStructureMasse(calculMasseStructure());
		vaiss.setBlindageMasse(calculMasseBlindage());
		
		vaiss.setMasseRestante(calculMasseDisponible());
	}
	
	@Override
	public void majEquipage() {
		vaiss.setEquipageArmement(calcEquip.getEquipageArmement(vaiss));
		vaiss.setEquipageKF(calcEquip.getEquipageKf(vaiss));
		vaiss.setEquipageMaintenance(calcEquip.getEquipageMaintenance(vaiss));
		vaiss.setEquipagePasserelle(calcEquip.getEquipagePasserelle(vaiss));
		vaiss.setEquipagePropulsion(calcEquip.getEquipagePropulsion(vaiss));
		vaiss.setEquipageDivers(calcEquip.getEquipageDivers(vaiss));
		
		long equipageTotal = 0;
		equipageTotal += vaiss.getEquipageArmement();
		equipageTotal += vaiss.getEquipageDivers();
		equipageTotal += vaiss.getEquipageKF();
		equipageTotal += vaiss.getEquipageMaintenance();
		equipageTotal += vaiss.getEquipagePasserelle();
		equipageTotal += vaiss.getEquipagePropulsion();
		
		vaiss.setEquipageTotal(equipageTotal);
	}

	public void majStatistique() {
		// on passe par une classe temporaire
		Vaisseau vaisseau = new Vaisseau();
		
		List<Sabord> sabords = new LinkedList<Sabord>();
		
		for (SabordCstr sab : vaiss.getSabords()) {
			sabords.add(sab);
		}
		
		vaisseau.setSabords(sabords);
		
		vaiss.setPuissanceArc(StatistiqueBatiment.calculPuissances(vaisseau));
		//System.out.println("majStatistique : " + vaiss.getPuissanceArc());
	}


	@Override
	public void majSabords() {
		List<SabordCstr> sabords = vaiss.getSabords();
		long integrite = vaiss.getStructureIntegrite();
		
		for (SabordCstr sabord : sabords) {
			sabord.setEmplacementMax(integrite*INT_EMPLAC);
			List<Equipement> arms = sabord.getArmements();
			long occupe = 0;
			for (Equipement equip : arms) {
				occupe += ((Armement)equip).getEncombrement();
			}
			sabord.setEmplacementDispo((integrite*INT_EMPLAC)-occupe);
		}
	}
	
	


}
